package de.slothsoft.commons.swing;

import javax.swing.ComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import de.slothsoft.commons.IDisplayable;
import de.slothsoft.commons.swing.databinding.DataBinding;
import de.slothsoft.commons.swing.util.ControlUtil;
import de.slothsoft.commons.swing.validation.IValidationListener;
import de.slothsoft.commons.swing.validation.IValidationListener.ValidationEvent;
import de.slothsoft.commons.swing.validation.ValidationBinding;

public abstract class AbstractDataBindingPanel<T> extends JPanel {

	private static final long serialVersionUID = 1L;

	private ValidationBinding validationBinding;
	private DataBinding<T> dataBinding;
	private T model;

	public AbstractDataBindingPanel(T model) {
		this.model = model;
		createControls(this);
	}

	protected final void createControls(JPanel mainPanel) {
		this.validationBinding = new ValidationBinding();
		this.validationBinding.addListener(new IValidationListener() {

			@Override
			public void validationChanged(ValidationEvent event) {
				performValidationChanged(event);
			}
		});
		this.dataBinding = new DataBinding<>(this.model);
		createControls(mainPanel, this.dataBinding, this.validationBinding);
		this.dataBinding.updateTargets();
		this.validationBinding.validate();
	}

	protected void performValidationChanged(ValidationEvent event) {
		// could be overriden
	}

	protected abstract void createControls(JPanel mainPanel, DataBinding<T> dataBinding,
			ValidationBinding validationBinding);

	public void updateModels() {
		this.dataBinding.updateModels();
	}

	public void updateTargets() {
		this.dataBinding.updateTargets();
	}

	public DataBinding<T> getDataBinding() {
		return this.dataBinding;
	}

	public ValidationBinding getValidationBinding() {
		return this.validationBinding;
	}

	public void setModel(T model) {
		this.model = model;
		this.dataBinding.setModel(model);
		updateTargets();
	}

	public T getModel() {
		return this.model;
	}

	public T getUpdatedModel() {
		updateModels();
		return getModel();
	}

	protected JTextField createText(JComponent component, String property, int x, int y) {
		JTextField textField = ControlUtil.createText(component, x, y);
		this.dataBinding.bind(textField, this.model, property);
		return textField;
	}

	protected JTextField createPassword(JComponent component, String property, int x, int y) {
		JTextField textField = ControlUtil.createPassword(component, x, y);
		this.dataBinding.bind(textField, this.model, property);
		return textField;
	}

	protected JTextArea createTextArea(JComponent component, String property, int x, int y) {
		JTextArea textArea = ControlUtil.createTextArea(component, x, y);
		textArea.setWrapStyleWord(true);
		textArea.setLineWrap(true);
		this.dataBinding.bind(textArea, this.model, property);
		return textArea;
	}

	protected JCheckBox createCheckBox(JComponent component, String property, int x, int y) {
		JCheckBox check = ControlUtil.createCheckBox(component, x, y);
		this.dataBinding.bind(check, this.model, property);
		return check;
	}

	protected <S> JComboBox<S> createCombo(JComponent parent, String property, ComboBoxModel<S> model, int x, int y) {
		JComboBox<S> combo = ControlUtil.createCombo(parent, model, x, y);
		this.dataBinding.bind(combo, this.model, property);
		return combo;
	}

	protected <U extends IDisplayable> JCheckList<U> createCheckList(JComponent parent, String property, U[] elements,
			int x, int y) {
		JCheckList<U> checkList = ControlUtil.createCheckList(parent, elements, x, y);
		this.dataBinding.bind(checkList, this.model, property);
		return checkList;
	}

}
